package com.jztd.servone.invoice.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.jztd.platfrom.base.exception.BusinessException;
import com.jztd.platfrom.base.exception.InvalidArgumentException;
import com.jztd.servone.emun.InvoicePartyCodeEnum;
import com.jztd.servone.emun.InvoiceStatusEnum;
import com.jztd.servone.invoice.dto.InvoiceRecordDTO;
import com.jztd.servone.invoice.dto.PTConfigDTO;
import com.jztd.servone.invoice.dto.ZPYConfigDTO;
import com.jztd.servone.invoice.param.ApplyInvoiceDetailsParam;
import com.jztd.servone.invoice.param.CancelInvoiceParam;
import com.jztd.servone.invoice.po.InvoicePartyConfig;
import com.jztd.servone.invoice.po.InvoiceRecord;
import com.jztd.servone.invoice.service.InvoicePartyConfigService;
import com.jztd.servone.invoice.service.InvoiceRecordService;
import com.jztd.servone.invoice.service.InvoiceService;
import com.jztd.servone.invoice.util.invoice.OpenApi;
import com.jztd.servone.invoice.util.invoice.SecurityUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;

/**票通开具发票*/
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class PTInvoiceServiceImpl implements InvoiceService {
    private final InvoicePartyConfigService invoicePartyConfigService;
    private final InvoiceRecordService invoiceRecordService;
    @Override
    public InvoiceRecord applyInvoice(ApplyInvoiceDetailsParam param) {
        invoiceRecordService.checkInvoiceResults(param.getInvoiceCodes());
        InvoiceRecord invoiceRecord = Convert.convert(InvoiceRecord.class, param);
        InvoicePartyConfig invoicePartyConfig = invoicePartyConfigService.getInvoicePartyConfig(param.getClientCode());
        PTConfigDTO configDTO = Convert.convert(PTConfigDTO.class, JSONUtil.parseObj(invoicePartyConfig.getConfigData()));

        invoiceRecord.setTaxpayerNum(invoicePartyConfig.getTaxpayerNum());
        // 生成流水号 = 生成14位时间戳（精确到秒：yyyyMMddHHmmss） + 随机数补位
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String timestamp = sdf.format(new Date());
        // 生成2位随机数（10-99），确保2位长度
        int randomNum = ThreadLocalRandom.current().nextInt(10, 100);
        invoiceRecord.setInvoiceReqSerialNo("ZLHP" + timestamp + randomNum);
        invoiceRecord.setInvoiceAmount(param.getTotalAmount());
        invoiceRecord.setTaxRateValue(configDTO.getTaxRateValue());
        invoiceRecord.setTradeNo(param.getInvoiceCodes());
        invoiceRecord.setInvoiceTime(new Date());
        invoiceRecord.setInvoiceIssueKindCode(configDTO.getTaxClassificationCode());
        invoiceRecord.setPreferentialPolicyFlag(configDTO.getPreferentialPolicyFlag());
        invoiceRecord.setVatSpecialManage(configDTO.getVatSpecialManage());
        invoiceRecord.setGoodsName(param.getProjectName());

        String url = invoicePartyConfig.getUrl()+"/invoiceBlue.pt";
        Map<String, Object> invoiceData = new HashMap<>();
        invoiceData.put("taxpayerNum", invoicePartyConfig.getTaxpayerNum());
        invoiceData.put("invoiceReqSerialNo", invoiceRecord.getInvoiceReqSerialNo());
        invoiceData.put("invoiceIssueKindCode", 82);
        invoiceData.put("buyerName", param.getBuyerName());//购买方名称
        if (ObjectUtil.isNotEmpty(param.getBuyerTaxpayerNum())){
            invoiceData.put("buyerTaxpayerNum", param.getBuyerTaxpayerNum());//购买方纳税人识别号
        }
        if (ObjectUtil.isNotEmpty(param.getTakerEmail())){
            invoiceData.put("takerEmail", param.getTakerEmail());
        }
        if (ObjectUtil.isNotEmpty(param.getRemark())){
            invoiceData.put("remark", param.getRemark());//备注
        }
        invoiceData.put("tradeNo", param.getInvoiceCodes());//订单号
        // 构建 itemList
        Map<String, String> item = new HashMap<>();
        item.put("goodsName", param.getProjectName());
        item.put("taxClassificationCode", configDTO.getTaxClassificationCode());//对应税收分类编码
        item.put("includeTaxFlag", "1");//是否含税，0不含税，1含税
        item.put("invoiceAmount", param.getTotalAmount().toString());//金额
        item.put("taxRateValue", String.valueOf(configDTO.getTaxRateValue()));//税率，例：0.13
        if (ObjectUtil.isNotEmpty(configDTO.getPreferentialPolicyFlag())){
            item.put("preferentialPolicyFlag", configDTO.getPreferentialPolicyFlag());//优惠政策标识：0.1.2，默认选1
        }
        if (ObjectUtil.isNotEmpty(configDTO.getVatSpecialManage())){
            item.put("vatSpecialManage", configDTO.getVatSpecialManage());//增值税特殊管理：免税、不征税、简易征收 ，默认选简易征收
        }

        List<Map<String, String>> itemList = new ArrayList<>();
        itemList.add(item);
        invoiceData.put("itemList", itemList);
        // 构建 passengerTransportList
        if (ObjectUtil.isNotEmpty(param.getTraveler())){
            Map<String, String> passengerTransport = new HashMap<>();
            passengerTransport.put("traveler", param.getTraveler());//出行人
            passengerTransport.put("travelDate", param.getTravelDate());//出行日期。格式yyyy-MM-dd
            passengerTransport.put("travelerIdType", "201");//出行证件类型：201.居民身份证，202.军官证，208.外国护照
            passengerTransport.put("travelerIdNo", param.getTravelerIdNo());//出行人证件号码
            passengerTransport.put("departurePlace", param.getDeparturePlace());//出发地
            passengerTransport.put("destinationPlace", param.getDestinationPlace());//到达地
            passengerTransport.put("vehicleType", param.getVehicleType());//交通工具类型:1:飞机；2:火车；3:长途汽车；4:公共交通；5:出租车；6:汽车；7:船舶；9:其他

            List<Map<String, String>> passengerTransportList = new ArrayList<>();
            passengerTransportList.add(passengerTransport);
            invoiceData.put("passengerTransportList", passengerTransportList);
        }
        String jsonStr = JSONUtil.toJsonPrettyStr(invoiceData);
        log.info("请求内容为:" + jsonStr);
        String buildRequest = new OpenApi(invoicePartyConfig.getPassword(), configDTO.getPlatformCode(), configDTO.getPlatformAlias(), invoicePartyConfig.getPrivateKey()).buildRequest(jsonStr);
        log.info("buildRequest参数:" + JSONUtil.toJsonPrettyStr(buildRequest));
        String response = HttpUtil.post( url, buildRequest);
        log.info("返回内容:{}"+JSONUtil.toJsonPrettyStr(response));
        JSONObject jsonObject = new JSONObject(response);
        Object code = jsonObject.get("code");
        String msg = jsonObject.getStr("msg");
        Object content = jsonObject.get("content");
        String decrypted = SecurityUtil.decrypt3DES(invoicePartyConfig.getPassword(), content.toString());
        log.info("解密content:{}"+JSONUtil.toJsonPrettyStr(decrypted));
        JSONObject jsonObject2 = new JSONObject(decrypted);
        if (code.equals("0000")){
            invoiceRecord.setInvoiceStatus(InvoiceStatusEnum.IN_PROGRESS.getCode());
            Object qrCodePath = jsonObject2.get("qrCodePath");
            invoiceRecord.setInvoiceUrl(Base64.decodeStr(qrCodePath.toString()));
        }else {
            invoiceRecord.setInvoiceStatus(InvoiceStatusEnum.FAIL.getCode());
        }
        invoiceRecord.setInvoiceFailureReason(msg);
        return invoiceRecord;
    }

    @Override
    public Boolean cancelInvoice(CancelInvoiceParam param) {
        InvoiceRecord invoiceRecord = invoiceRecordService.getInvoiceRecordById(param.getInvoiceRecordId());
        invoiceRecord.setRedReason(param.getRedReason());
        invoiceRecord.setFlushTime(new Date());
        String taxpayerNum = invoiceRecord.getTaxpayerNum();
        String invoiceCode = invoiceRecord.getInvoiceCode();
        String invoiceNo = invoiceRecord.getInvoiceNo();
        String redReason = param.getRedReason();
        BigDecimal invoiceAmount = invoiceRecord.getInvoiceAmount();
        BigDecimal redAmount = invoiceAmount.negate();
        // 前置校验
        if (ObjectUtil.isEmpty(invoiceCode) || ObjectUtil.isEmpty(invoiceNo)) {
            throw new BusinessException("暂无法冲红该发票，请稍后再重试");
        }
        if (!Arrays.asList("01", "02", "03").contains(redReason)) {
            throw new BusinessException("请选择正确的作废原因");
        }
        InvoicePartyConfig invoicePartyConfig = invoicePartyConfigService.getInvoicePartyConfig(param.getClientCode());
        PTConfigDTO configDTO = Convert.convert(PTConfigDTO.class, JSONUtil.parseObj(invoicePartyConfig.getConfigData()));

        String url = invoicePartyConfig.getUrl();
        Map<String, Object> invoiceData = new HashMap<>();
        invoiceData.put("taxpayerNum", taxpayerNum);
        invoiceData.put("invoiceReqSerialNo", invoiceRecord.getInvoiceReqSerialNo());
        invoiceData.put("invoiceCode", invoiceCode);
        invoiceData.put("invoiceNo", invoiceNo);
        invoiceData.put("redReason", redReason);// 01：开票有误;02：销货退回;03：服务中止
        invoiceData.put("amount", redAmount);// 原发票的价税合计金额的负数值

        String jsonStr = JSONUtil.toJsonPrettyStr(invoiceData);
        String buildRequest = new OpenApi(invoicePartyConfig.getPassword(), configDTO.getPlatformCode(), configDTO.getPlatformAlias(), invoicePartyConfig.getPrivateKey()).buildRequest(jsonStr);
        log.info("buildRequest参数:" + JSONUtil.toJsonPrettyStr(buildRequest));

        String response = HttpUtil.post(url, buildRequest);
        log.info("返回内容:" + JSONUtil.toJsonPrettyStr(response));
        JSONObject jsonObject = new JSONObject(response);
        Object code = jsonObject.get("code");
        Object msg = jsonObject.get("msg");

        if ("0000".equals(code)) {
            invoiceRecord.setInvoiceStatus(InvoiceStatusEnum.CANCELED.getCode());
        } else {
            log.info("发票冲红失败：{}，原因：{}", invoiceRecord.getId(), msg);
            invoiceRecordService.updateInvoiceRecord(invoiceRecord);
            throw new BusinessException("冲红失败："+msg);
        }
        invoiceRecordService.updateInvoiceRecord(invoiceRecord);
        return true;
    }

    @Override
    public InvoiceRecordDTO getInvoiceDetails(String invoiceCode) {
        if (ObjectUtil.isEmpty(invoiceCode)) {
            throw new InvalidArgumentException("发票号不能为空");
        }
       return null;
    }

    @Override
    public String getServiceType() {
        return InvoicePartyCodeEnum.PT_YA.name();
    }
}
